/***** Historian.m -- recorded data browser object implementation
	NeXTstep Measurement Kit
	by Alex Meyer <ameyer@phoenix.Princeton.EDU>
	for computer science senior thesis
	17 April 1992 -- created
	22 April 1992 -- incorporated structs.h & added more types
		utilized identify messages & centralized filename extension
	25 April 1992 -- hid presenter only when necessary to avoid flicker
*****/

#import <stdio.h>
#import <string.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/OpenPanel.h>
#import "Historian.h"

@implementation Historian

- hideVisible
{
	if (visPresent) {
		[visPresent hide:self];
		visPresent = nil;
	}
	return (self);
}

- buildHierarchy
{
	unsigned i,num;

	num = [manager numRecords];
	for (i = 0;i < num;++i) {
		id store;
		tmRec rec;

		[manager copyRecordIndex:i
			into:&rec];
		store = indices[rec.type];
		[store addElement:&i];
	}
	return (self);
}


- destroyHierarchy
{
	int i;

	for (i = 1;i < TM_NUM;++i)
		[indices[i] empty];
	return (self);
}


- selectType:(NXAtom)key
{
	int i;

	type = TM_ERR;
	for (i = 1;i < TM_NUM;++i)
		if (key == [presenters[i] identify])
			type = i;
	return (self);
}


- selectRecord:(NXAtom)key
{
	if (type != TM_ERR) {
		BOOL res;
		unsigned ind;

		res = [manager findIndex:&ind
			ofKey:key
			andType:type];
		if (res) {
			index = ind;
			visPresent = presenters[type];
			[visPresent showData:self];
			return (self);
		}
	}
	return (nil);
}


- determineType
{
	int col;

	col = [browser selectedColumn];
	if (col == 0) {
		id matrix,cell;
		NXAtom key;

		matrix = [browser matrixInColumn:0];
		cell = [matrix selectedCell];
		key = NXUniqueString([cell stringValue]);
		[self selectType:key];
	}
	return (self);
}


- (BOOL)openFilename:(const char *)fname
{
	id res;

	if (opened)
		return (NO);
	[manager setFile:NXUniqueString(fname)];
	res = [manager load];
	if (res) {
		[self buildHierarchy];
		opened = YES;
		type = TM_ERR;
		[window setTitleAsFilename:fname];
		[openMenuCell setEnabled:NO];
		[closeMenuCell setEnabled:YES];
		[browser loadColumnZero];
		return (YES);
	}
	[manager close];
	return (NO);
}


- (int)app:sender
	openFile:(const char *)filename
	type:(const char *)aType
{
	BOOL res;

	if (strcmp(aType,FILEEXT))
		return (NO);
	res = [self openFilename:filename];
	return (res);
}


- (BOOL)appAcceptsAnotherFile:sender
{
	return (!(opened));
}


- appWillInit:sender
{
	int i;

	manager = [TranscriptManager alloc];
	[manager init];
	indices[TM_ERR] = nil;
	for (i = 1;i < TM_NUM;++i) {
		indices[i] = [Storage alloc];
		[indices[i] initCount:0
			elementSize:sizeof(unsigned)
			description:NULL];
	}
	presenters[TM_ERR] = nil;
	presenters[TM_BUTTON] = [ButtonPresenter new];
	presenters[TM_SLIDER] = [SliderPresenter new];
	presenters[TM_SCROLLER] = [ScrollerPresenter new];
	presenters[TM_MENU] = [MenuPresenter new];
	visPresent = nil;
	opened = NO;
	type = TM_ERR;
	return (self);
}


- appWillTerminate:sender
{
	int i;

	[self hideVisible];
	for (i = 1;i < TM_NUM;++i)
		[indices[i] free];
	/* should try to free presenters too */
	[manager free];
	return (self);
}


- (int)browser:sender
	fillMatrix:matrix
	inColumn:(int)column
{
	id cell;
	int rows,cols;

	if (!(opened))
		return (0);
	if (column == 0) {
		int i;
		NXAtom key;

		for (i = 1;i < TM_NUM;++i) {
			[matrix addRow];
			[matrix getNumRows:&rows
				numCols:&cols];
			cell = [matrix cellAt:rows - 1
				:0];
			key = [presenters[i] identify];
			[cell setStringValue:key];
			[cell setLoaded:YES];
			[cell setLeaf:NO];
		}
		return (TM_NUM - 1);
	}
	else {
		id store;
		unsigned i,num;

		[self determineType];	/* because of oddity in NXBrowser */
		store = indices[type];
		num = [store count];
		for (i = 0;i < num;++i) {
			tmRec rec;
			unsigned *Ind;

			Ind = [store elementAt:i];
			[manager copyRecordIndex:*Ind
				into:&rec];
			[matrix addRow];
			[matrix getNumRows:&rows
				numCols:&cols];
			cell = [matrix cellAt:rows - 1
				:0];
			[cell setStringValue:rec.key];
			[cell setLoaded:YES];
			[cell setLeaf:YES];
		}
		return (num);
	}
}


- cellSelected:sender
{
	int col;

	col = [browser selectedColumn];
	if (col >= 0) {
		id matrix,cell;
		NXAtom key;

		matrix = [browser matrixInColumn:col];
		cell = [matrix selectedCell];
		key = NXUniqueString([cell stringValue]);
		if (col == 0) {
			[self hideVisible];
			[self selectType:key];
		}
		else
			[self selectRecord:key];
	}
	return (self);
}


- openDoc:sender
{
	id panel;
	int succ;
	char *fileType;
	char *dir;
	char **fileList;
	char temp[512];
	char *typeList[2];

	panel = [OpenPanel new];
	[panel allowMultipleFiles:NO];
	fileType = FILEEXT;
	typeList[0] = fileType;
	typeList[1] = NULL;
	succ = [panel runModalForTypes:typeList];
	if (succ) {
		fileList = [panel filenames];
		dir = [panel directory];
		sprintf(temp,"%s/%s",dir,*fileList);
		[self openFilename:temp];
	}
	return (self);
}


- closeDoc:sender
{
	[self hideVisible];
	[manager close];
	[self destroyHierarchy];
	opened = NO;
	type = TM_ERR;
	[window setTitle:"Historian"];
	[openMenuCell setEnabled:YES];
	[closeMenuCell setEnabled:NO];
	[browser loadColumnZero];
	return (self);
}


- copyDataTo:(void *)dst;
{
	tmRec rec;
	[manager copyRecordIndex:index
		into:&rec];
	memcpy(dst,rec.Stats,rec.statsSize);
	return (self);
}


- (NXAtom)getKey
{
	tmRec rec;

	[manager copyRecordIndex:index
		into:&rec];
	return (rec.key);
}

@end
